package cn.cellcom.agent.online.wrapper;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.cellcom.agent.common.AgentConstant;
import cn.cellcom.agent.common.AgentConstant.AGENT_TALKING_POLICY;
import cn.cellcom.agent.common.AgentConstant.MEMBER_STATUS;
import cn.cellcom.agent.common.AgentConstant.SELF_RESPONSE;
import cn.cellcom.agent.entity.TSettingEntity;
import cn.cellcom.agent.j2ee.AgentListener;
import cn.cellcom.agent.online.client.AgentClient;
import cn.cellcom.agent.online.client.Client;
import cn.cellcom.agent.online.client.SessionManager;
import cn.cellcom.agent.online.client.SystemClient;
import cn.cellcom.agent.online.client.VisitorClient;
import cn.cellcom.agent.online.message.ChatMessage;
import cn.cellcom.agent.online.message.MessageConstant;
import cn.cellcom.agent.online.message.MessageConstant.MESSAGE_EVENT;
import cn.cellcom.agent.online.message.MessageConstant.MESSAGE_NOTIFY;
import cn.cellcom.agent.pojo.TAgentSession;
import cn.cellcom.agent.pojo.TCrm;
import cn.cellcom.agent.pojo.TSession;
import cn.cellcom.jar.util.AU;
import cn.cellcom.jar.util.MyException;

/**
 * 封装会话
 * 
 * @author zhengyj
 * 
 */
public class SessionWrapper {
	private Logger log = LoggerFactory.getLogger(this.getClass());

	public SessionWrapper(TSession session, TSettingEntity setting) {
		this.session = session;
		this.setting = setting;
		agsessions = new HashMap<String, AgSessionWrapper>();
		this.system = new SystemClient(this);
	}

	private long lastVisitorMessage = System.currentTimeMillis();
	private long lastAgentMessage = System.currentTimeMillis();

	/**
	 * 表示第一次进入自助（刷新页面之后会变）
	 */
	private boolean firstSelf = true;

	/**
	 * 发送过静默提示，则不再重复发送
	 */
	private boolean sentSilentNotice = false;

	/**
	 * 如果正在处理静默结束【执行过程可能有点时间】，则不再重复调用
	 */
	private boolean silentEnding = false;
	// private boolean firstGetGroupList = true;

	private TSettingEntity setting;

	private TSession session;

	private SystemClient system;

	private Map<String, AgSessionWrapper> agsessions;

	private GroupWrapper group;

	private VisitorClient visitor;

	private TCrm crm = null;

	// Table-field, recordid-value
	private Map<String, WRITE_BACK_INFO> writeBack = new HashMap<String, WRITE_BACK_INFO>();

	private int unknowResponse = 0;

	/**
	 * 标记访客是否进入过，对于坐席手中的老会话，该参数是false。 这个参数决定是否还需要下发静默
	 */
	private boolean visitorComed = false;

	/**
	 * 正在邀请的坐席(id)
	 */
	private Set<String> invitingAgents = new HashSet<String>();

	/**
	 * 会话的事件
	 */
	private MESSAGE_EVENT event;

	public class WRITE_BACK_INFO {
		private String table;

		private String field;

		private String id;

		private String value;

		private String addOrUpdate;

		public WRITE_BACK_INFO(String table, String field, String id, String value, String addOrUpdate) {
			this.table = table;
			this.field = field;
			this.id = id;
			this.value = value;
			this.addOrUpdate = addOrUpdate;
		}

		public String getTable() {
			return table;
		}

		public void setTable(String table) {
			this.table = table;
		}

		public String getField() {
			return field;
		}

		public void setField(String field) {
			this.field = field;
		}

		public String getId() {
			return id;
		}

		public void setId(String id) {
			this.id = id;
		}

		public String getValue() {
			return value;
		}

		public void setValue(String value) {
			this.value = value;
		}

		public String getAddOrUpdate() {
			return addOrUpdate;
		}

		public void setAddOrUpdate(String addOrUpdate) {
			this.addOrUpdate = addOrUpdate;
		}
	}

	/**
	 * 在线的坐席数量
	 * 
	 * @return
	 */
	public int getAgsessionSize() {
		return agsessions.size();
	}

	public void setAgsessions(Map<String, AgSessionWrapper> agsessions) {
		this.agsessions = agsessions;
	}

	public TSettingEntity getSetting() {
		return setting;
	}

	public void setSetting(TSettingEntity setting) {
		this.setting = setting;
	}

	public SystemClient getSystem() {
		return system;
	}

	public boolean isSentSilentNotice() {
		return sentSilentNotice;
	}

	public void setSentSilentNotice(boolean sentSilentNotice) {
		this.sentSilentNotice = sentSilentNotice;
	}

	public boolean isSilentEnding() {
		return silentEnding;
	}

	public void setSilentEnding(boolean silentEnding) {
		this.silentEnding = silentEnding;
	}

	public VisitorClient getVisitor() {
		return visitor;
	}

	public boolean isFirstSelf() {
		return firstSelf;
	}

	public void setFirstSelf(boolean firstSelf) {
		this.firstSelf = firstSelf;
	}

	public String getPid() {
		return session.getPid();
	}

	public void setSession(TSession session) {
		this.session = session;
	}

	public String getId() {
		return session.getId();
	}

	public GroupWrapper getGroup() {
		return group;
	}

	public void setGroup(GroupWrapper group) {
		this.group = group;
	}

	public TSession getSession() {
		return session;
	}

	public long getLastVisitorMessage() {
		return lastVisitorMessage;
	}

	public void setLastVisitorMessage() {
		this.lastVisitorMessage = System.currentTimeMillis();
		this.setSentSilentNotice(false);
	}

	public long getLastAgentMessage() {
		return lastAgentMessage;
	}

	public void setLastAgentMessage() {
		this.lastAgentMessage = System.currentTimeMillis();
	}

	/**
	 * 创建坐席的会话
	 * 
	 * @param agsession
	 * @param agclient
	 * @return
	 */
	public AgSessionWrapper joinAgsession(TAgentSession agsession, AgentClient agclient, boolean newJoin) {
		AgSessionWrapper exist = agsessions.get(agsession.getId());
		if (exist == null) {
			exist = new AgSessionWrapper(agsession, agclient);
			agsessions.put(agclient.getId(), exist);
		}
		this.join(agclient, newJoin);
		return exist;
	}

	/**
	 * 成员进入会话，然后通知在线成员（包括自己）
	 * 
	 * @param client
	 */
	public void join(Client client, Boolean newJoin) {
		log.info("[{}] join the session[{}] by wrapper[{}]", client.getId(), this.getId(), this);
		if (client instanceof VisitorClient) {// 访客进入，通知坐席，也把当前的坐席通知访客
			visitorComed = true;
			client.getIdMap().put(this.getPid(), this.getId());
			newJoin = visitor == null;// 如果原来没在，则认为是首次进入
			// 只有visitor为空的时候相互通知，刷新界面时候不需要提示
			visitor = (VisitorClient) client;
			this.setCrm(visitor.getCrm());
			for (AgSessionWrapper agsession : agsessions.values()) {
				AgentClient agent = agsession.getAgclient();
				if (agent != null) {
					system.sysSendMemberOnline(client.getId(), agent.getId(), AgentConstant.USER_TYPE_AGENT, agent.getNickname());
					if (newJoin) {// 首次进入方通知坐席，访客刷新界面不需要通知
						system.sysSendMemberOnline(agent.getId(), client.getId(), AgentConstant.USER_TYPE_VISITOR, visitor.getNickname());
					}
				}
			}
		} else {// 坐席进入
			client.getIdMap().put(session.getCrm(), this.getId());

			/*
			 * boolean monitor = false; for (AgSessionWrapper agsession :
			 * agsessions.values()) { if
			 * (agsession.getAgclient().getId().equals(client.getId())) { if
			 * (AgentConstant.AGENT_JOIN_TYPE.AGENT_MONITOR.name().equals(agsession.getAgsession().getJoinType())) {
			 * monitor = true; break; } } }
			 */

			AgentClient agentClient = (AgentClient) client;
			// 告知访客有坐席进入，也告知坐席访客在线
			if (visitor != null) {
				if (newJoin) {// 首次进入才通知访客
					system.sysSendMemberOnline(visitor.getId(), agentClient.getId(), AgentConstant.USER_TYPE_AGENT, agentClient.getNickname());
				}
				system.sysSendMemberOnline(agentClient.getId(), visitor.getId(), AgentConstant.USER_TYPE_VISITOR, visitor.getNickname());
			} else {// 访客不在线，则要通知坐席：访客的状态为END或者OFFLINE
				MEMBER_STATUS status = session.getEndTime() == null ? MEMBER_STATUS.OFFLINE : MEMBER_STATUS.END;
				system.sysSendMemberStatus(agentClient.getId(), session.getCrm(), AgentConstant.USER_TYPE_VISITOR, status);
			}

			// 坐席进入，则通知该坐席当前会话中的坐席，这个是群聊处理，TODO
			for (AgSessionWrapper agsession : agsessions.values()) {
				AgentClient otherAgent = agsession.getAgclient();
				if (otherAgent != null) {
					if (otherAgent.getId().equals(client.getId())) {
					} else {
						system.sysSendMemberOnline(agentClient.getId(), otherAgent.getId(), AgentConstant.USER_TYPE_AGENT, otherAgent.getNickname());

						system.sysSendMemberOnline(otherAgent.getId(), agentClient.getId(), AgentConstant.USER_TYPE_AGENT, agentClient.getNickname());
					}
				}
			}
		}
	}

	/**
	 * 成员离开，然后通知在线成员（当然不包括自己）
	 * 
	 * @param client
	 */
	public void left(Client client, AgentConstant.MEMBER_STATUS status) {
		log.info("[{}] left the session[{}] by status[{}]", client.getId(), this.getId(), status);
		boolean visitorLeft = client instanceof VisitorClient;
		boolean agentLeft = client instanceof AgentClient;
		if (agentLeft && visitor != null) {// 坐席离开通知访客
			system.sysSendMemberStatus(visitor.getId(), client.getId(), AgentConstant.USER_TYPE_AGENT, status);
		}
		// 通知所有坐席
		for (AgSessionWrapper agsession : agsessions.values()) {
			AgentClient agent = agsession.getAgclient();
			if (visitorLeft) {// 访客离开通知坐席
				system.sysSendMemberStatus(agent.getId(), visitor.getId(), AgentConstant.USER_TYPE_VISITOR, status);
			} else {// 坐席离开通知其他坐席
				if (!agsession.getAgclient().getId().equals(client.getId())) {
					system.sysSendMemberStatus(agent.getId(), client.getId(), AgentConstant.USER_TYPE_AGENT, status);
				}
			}
		}

		if (visitorLeft) {
			client.getIdMap().remove(session.getPid());
			visitor = null;
		} else {
			client.getIdMap().remove(session.getCrm());
			agsessions.remove(client.getId());
		}
		// 所有成员已经不在线&& (|| (agsessions.size() == 1 &&
		// agsessions.get(0).getAgsession().getJoinType().equals(AgentConstant.AGENT_JOIN_TYPE.AGENT_MONITOR.name())))
		if (visitor == null && agsessions.size() == 0) {
			log.info("[{}] remove the session[{}] from SessionManager because no any body in session.", client.getId(), this.getId());
			this.system = null;

			SessionManager.getInstance().getPool(this.getPid()).removeSession(this.getId());
			// 将消息数量写入数据库
			this.writeBack();
		}
	}

	/**
	 * 系统对访客静默执行关闭会话时调用,通知在线坐席
	 */
	public void notifyToAgentForSilentEnd() {
		// 通知所有坐席
		for (AgSessionWrapper agsession : agsessions.values()) {
			AgentClient agent = agsession.getAgclient();
			system.sysSendMemberStatus(agent.getId(), session.getCrm(), AgentConstant.USER_TYPE_VISITOR, MEMBER_STATUS.END);
		}
	}

	/**
	 * 对于坐席退出会话的,需要发送消息通知其他坐席
	 */
	public void notifyToAgentForLelfSession() {
		// 通知所有会话中的坐席
		for (AgSessionWrapper ags : agsessions.values()) {
			system.sysSendNotify(ags.getAgclient().getId(), MESSAGE_NOTIFY.AG_INVITE_AGENT_END, null);
		}
	}

	/**
	 * 在会话中发出消息
	 * 
	 * @param senderClient
	 * @param text 发送的消息
	 */
	public void message(Client senderClient, String text, String value2, String multiType) {
		if (senderClient instanceof VisitorClient) {// 访客给所有坐席发送消息
			setLastVisitorMessage();

			TSettingEntity setting = this.getSetting();
			TSession s = this.getSession();
			// 自助聊天，需要系统回复
			if (s.getStep().equals(AgentConstant.SESSION_STEP.SELF.name())) {
				// 订单或者语音每天，则自动转人工座席
				if (MessageConstant.MULIT_TYPE.ORDER.name().equals(multiType) || MessageConstant.MULIT_TYPE.AUDIO.name().equals(multiType)) {
					if (this.getGroup() != null && this.getGroup().countAgents() > 0) {
						log.info("[{}] send order/audio message in session[], so auto change to manual.", this.getCrm().getId(), this.getId());
						this.system.sysSendText(setting.getSelfAutoToManualTip());
						this.system.sysSendNotify(senderClient.getId(), MESSAGE_NOTIFY.AUTO_TO_MANUAL, null);
					} else {
						log.warn("[{}] send order/audio message in session[], but no any agent online.", this.getCrm().getId(), this.getId());
					}
				} else {
					// 自动转人工
					if (AU.isExist(setting.getKeyWordToManual().split(","), text, null) >= 0) {
						if (this.getGroup() != null && this.getGroup().countAgents() > 0) {
							log.info("[{}] send the special key in session[], so auto change to manual.", this.getCrm().getId(), this.getId());
							this.system.sysSendText(setting.getSelfAutoToManualTip());
							this.system.sysSendNotify(senderClient.getId(), MESSAGE_NOTIFY.AUTO_TO_MANUAL, null);
						} else {
							log.warn("[{}] send the special key in session[], but no any agent online.", this.getCrm().getId(), this.getId());
						}
					} else {
						SELF_RESPONSE result = ((VisitorClient) senderClient).getChatHandler().handleSelfResponse(this, text, value2);
						// 0回复则累计
						if (result.equals(SELF_RESPONSE.ZERO)) {
							unknowResponse++;
							if (unknowResponse >= setting.getSelfErrorLimit()) {
								if (this.getGroup() != null && this.getGroup().countAgents() > 0) {
									log.info("[{}] robot's unkown response over the limit in session[], so auto change to manual.", this.getCrm().getId(),
											this.getId());
									this.system.sysSendText(setting.getSelfAutoToManualTip());
									this.system.sysSendNotify(senderClient.getId(), MESSAGE_NOTIFY.AUTO_TO_MANUAL, null);
								} else {
									log.warn("[{}] robot's unkown response over the limit in session[], but no any agent online.", this.getCrm().getId(),
											this.getId());
								}
							}
						}
					}
				}
			} else if (s.getStep().equals(AgentConstant.SESSION_STEP.QUEUE.name())) {
				// 配置了排队时的自动回复固定某个设置提示语
				if (setting.getQueueTalkingPolicy() == AgentConstant.QUEUE_TALKING_POLICY.ENABLE_TIP.ordinal()) {
					if (StringUtils.isNotBlank(setting.getVisitorQueueTip())) {
						system.sysSendText(setting.getVisitorQueueTip());
					}
				} else if (setting.getQueueTalkingPolicy() == AgentConstant.QUEUE_TALKING_POLICY.ENABLE_SELF.ordinal() || StringUtils.isNotBlank(value2)) {// 配置了排队时自助回复或者选择常见问题
					((VisitorClient) senderClient).getChatHandler().handleSelfResponse(this, text, value2);
				}
			} else {
				for (AgSessionWrapper agsession : agsessions.values()) {
					AgentClient agent = agsession.getAgclient();
					ChatMessage bm = new ChatMessage(agent.getId(), text, multiType);
					bm.setPid(session.getPid());
					bm.setSid(session.getId());
					bm.setCid(session.getCrm());
					senderClient.sendBizMessage(bm);
				}
				if (s.getStep().equals(AgentConstant.SESSION_STEP.AGENT.name())) {
					// 坐席聊天支持自助回复
					if (AGENT_TALKING_POLICY.ENABLE_SELF.ordinal() == setting.getAgentTalkingPolicy() && StringUtils.isNotBlank(value2)) {
						((VisitorClient) senderClient).getChatHandler().handleSelfResponse(this, text, value2);
					}
				}
			}
			if (s.getStep().equals(AgentConstant.SESSION_STEP.AGENT.name())) {
				s.setMessageCountWhenAgent(s.getMessageCountWhenAgent() + 1);
			}
			s.setMessageCount(s.getMessageCount() + 1);
		} else if (senderClient instanceof AgentClient) {// 坐席给访客发送消息
			setLastAgentMessage();

			if (visitor != null) {
				ChatMessage bm = new ChatMessage(visitor.getId(), text, multiType);
				bm.setPid(session.getPid());
				bm.setSid(session.getId());
				bm.setCid(session.getCrm());
				senderClient.sendBizMessage(bm);
			}

			// 消息发给群聊中的其他人
			for (AgSessionWrapper agsession : agsessions.values()) {
				AgentClient otherAgent = agsession.getAgclient();
				if (!otherAgent.getId().equals(senderClient.getId())) {// 过滤自己
					ChatMessage bm = new ChatMessage(otherAgent.getId(), text, multiType);
					bm.setPid(session.getPid());
					bm.setSid(session.getId());
					bm.setCid(session.getCrm());
					senderClient.sendBizMessage(bm);
				}
			}

			TAgentSession agsession = this.getAgsession(senderClient.getId()).getAgsession();
			agsession.setMessageCount(agsession.getMessageCount() + 1);
			if (agsession.getFirstResponseTime() == null) {
				agsession.setFirstResponseTime(System.currentTimeMillis());
			}

			if (this.getSession().getFirstAgentResponseTime() == null) {
				this.getSession().setFirstAgentResponseTime(System.currentTimeMillis());
			}
			this.getSession().setAgentMessageCount(this.getSession().getAgentMessageCount() + 1);
		} else if (senderClient instanceof SystemClient) {// 系统发送的消息
			if (visitor != null) {
				ChatMessage bm = new ChatMessage(visitor.getId(), text, multiType);
				bm.setPid(session.getPid());
				bm.setSid(session.getId());
				bm.setCid(session.getCrm());
				senderClient.sendBizMessage(bm);
			}
			for (AgSessionWrapper agsession : agsessions.values()) {
				AgentClient agent = agsession.getAgclient();
				ChatMessage bm = new ChatMessage(agent.getId(), text, multiType);
				bm.setPid(session.getPid());
				bm.setSid(session.getId());
				bm.setCid(session.getCrm());
				senderClient.sendBizMessage(bm);
			}

			this.getSession().setSystemMessageCount(this.getSession().getSystemMessageCount() + 1);
		}
	}

	/**
	 * 获取排队超时
	 * 
	 * @return
	 */
	public long getQueueLimitTime() {
		if (getSetting().getQueueLimit() <= 0) {
			return System.currentTimeMillis() * 2;
		}
		return getSetting().getQueueLimit() * 60 * 1000;
	}

	public long getSilentNoticeLimitTime() {
		// 如果访客已经退出，那么这个会话应该是挂在坐席手中，不需要自动结束-----即便挂在坐席手中，也要自动结束哦
		if (getSetting().getSilentNoticeLimit() <= 0 || !session.getStep().equals(AgentConstant.SESSION_STEP.AGENT.name())) {
			return System.currentTimeMillis() * 2;
		}
		return getSetting().getSilentNoticeLimit() * 60 * 1000;
	}

	public long getSilentEndLimitTime() {
		// 如果访客已经退出，那么这个会话应该是挂在坐席手中，不需要自动结束------即便挂在坐席手中，也要自动结束哦
		if (getSetting().getSilentEndLimit() <= 0 || !session.getStep().equals(AgentConstant.SESSION_STEP.AGENT.name())) {
			return System.currentTimeMillis() * 2;
		}
		return getSetting().getSilentEndLimit() * 60 * 1000;
	}

	/**
	 * 获取坐席
	 * 
	 * @param id
	 * @return
	 */
	public AgSessionWrapper getAgsession(String id) {
		return this.agsessions.get(id);
	}

	/**
	 * 会话销毁时写会数据库
	 */
	public void writeBack() {
		for (String key : writeBack.keySet()) {
			WRITE_BACK_INFO back = writeBack.get(key);
			String hql = null;
			if (back.getAddOrUpdate().equals("add")) {
				hql = "update " + back.getTable() + " set " + back.getField() + "=" + back.getField() + "+" + back.getValue() + " where id = ?";
			} else {
				hql = "update " + back.getTable() + " set " + back.getField() + "=" + back.getValue() + " where id = ?";
			}
			String[] values = new String[] { back.getId() };
			try {
				AgentListener.getStaticDao().myExecute(hql, values);
			} catch (MyException e) {
				log.error("[{}] session update the write back fail.", this.getId(), e.getException());
			}
		}
	}

	/**
	 * 找到会话的主持人:首次接入会话,或者收到转接的坐席
	 * 
	 * @return
	 */
	public AgentClient getMastAgent() {
		//先找到原始的接入者
		for (AgSessionWrapper agsession : agsessions.values()) {
			if (agsession.getAgsession().getJoinType().equals(AgentConstant.AGENT_JOIN_TYPE.RECEIVE_QUEUE.name())) {
				return agsession.getAgclient();
			}
		}
		//找到被转接的主持人
		for (AgSessionWrapper agsession : agsessions.values()) {
			if (agsession.getAgsession().getJoinType().equals(AgentConstant.AGENT_JOIN_TYPE.AGENT_TRANSFER.name())) {
				return agsession.getAgclient();
			}
		}
		return null;
	}

	/**
	 * 访客的等级
	 * 
	 * @return
	 */
	public Integer getCrmLevel() {
		return visitor.getCrm().getLevel();
	}

	public TCrm getCrm() {
		return crm;
	}

	public void setCrm(TCrm crm) {
		this.crm = crm;
	}

	public boolean isVisitorComed() {
		return visitorComed;
	}

	public Set<String> getInvitingAgents() {
		return invitingAgents;
	}

	public Map<String, AgSessionWrapper> getAgsessions() {
		return agsessions;
	}

	public void setEvent(MESSAGE_EVENT eventType) {
		this.event = eventType;
	}

	public MESSAGE_EVENT getEvent() {
		return event;
	}

}
